﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

using Gurucore.Framework.Core;

namespace Gurucore.Framework.DataAccess.Persistence
{
	public class SingleDTOTransformer : DTOTransformer
	{
		public override List<T> Transform<T>(System.Data.IDataReader p_reader, T p_sample)
		{
			List<T> resultObjs = new List<T>();
			Type resultType = typeof(T);

			while (p_reader.Read())
			{
				T resultObj = (T)this.Transform(resultType, null, p_reader);
				resultObjs.Add(resultObj);
			}

			return resultObjs;
		}

		//virtual or not? performance considerable
		public virtual object Transform(Type p_objType, object p_sampleObj, System.Data.IDataReader p_reader)
		{
			TableInfoManager oTableInfoMgr = Application.GetInstance().GetGlobalSharedObject<TableInfoManager>();
			TableInfo oTableInfo = oTableInfoMgr.GetTableInfo(p_objType);

			object resultObj = null;
			if (p_sampleObj == null)
			{
				DTOProxier proxier = new DTOProxier();
				Type proxyType = proxier.GetProxyClass(p_objType);
				resultObj = Activator.CreateInstance(proxyType);
			}
			else
			{
				resultObj = p_sampleObj;
			}

			int nReadColumn = p_reader.FieldCount;

			for (int i = 0; i < nReadColumn; i++)
			{
				string sColumn = p_reader.GetName(i);
				if (oTableInfo.Property.ContainsKey(sColumn))
				{
					PropertyInfo oProperty = oTableInfo.Property[sColumn];
					if (p_reader[sColumn] != DBNull.Value)
					{
						if (oProperty.PropertyType == p_reader.GetFieldType(i))
						{
							oProperty.SetValue(resultObj, p_reader[i], null);
						}
						else
						{
							//support change type by mapping
							if (oProperty.PropertyType.IsPrimitive)
							{
								oProperty.SetValue(resultObj, Convert.ChangeType(p_reader[i], oProperty.PropertyType), null);
							}
							//support nullable, not recommended
							else if (oProperty.PropertyType.IsGenericType && oProperty.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
							{
								oProperty.SetValue(resultObj, Convert.ChangeType(p_reader[i], oProperty.PropertyType.GetGenericArguments()[0]), null);
							}
						}

						//note, use short column here
						((IManageableDTO)resultObj).SetColumnState(oProperty.Name, DTOColumnState.Unchanged);
					}
				}
			}

			return resultObj;
		}
	}
}
